# -*- coding: UTF-8 -*-
# !/usr/bin/python
# @time     :2019/8/26 10:02
# @author   :Mo
# @function :text summary of feature-base of TextTeaser
# @paper    :Automatic Text Summarization for Indonesian Language Using TextTeaser(2013)
# @url      :using Google Scholar


from nlg_yongzhuo.data_preprocess.text_preprocess import extract_chinese
from nlg_yongzhuo.data_preprocess.text_preprocess import cut_sentence
from nlg_yongzhuo.data_preprocess.text_preprocess import jieba_cut
from nlg_yongzhuo.data.stop_words.stop_words import stop_words
from collections import Counter


class TextTeaserSum:
    def __init__(self):
        self.algorithm = 'text_teaser'
        self.stop_words = stop_words.values()
        self.len_ideal = 18 # 中心句子长度, 默认

    def score_position(self):
        """
            文本句子位置得分
        :param sentence: 
        :return: 
        """
        score_position = []
        for i, sen in enumerate(self.sentences):
            score_standard = i / (len(self.sentences))
            if score_standard >= 0 and score_standard <= 0.1:
                score_position.append(0.17)
            elif score_standard > 0.1 and score_standard <= 0.2:
                score_position.append(0.23)
            elif score_standard > 0.2 and score_standard <= 0.3:
                score_position.append(0.14)
            elif score_standard > 0.3 and score_standard <= 0.4:
                score_position.append(0.08)
            elif score_standard > 0.4 and score_standard <= 0.5:
                score_position.append(0.05)
            elif score_standard > 0.5 and score_standard <= 0.6:
                score_position.append(0.04)
            elif score_standard > 0.6 and score_standard <= 0.7:
                score_position.append(0.06)
            elif score_standard > 0.7 and score_standard <= 0.8:
                score_position.append(0.04)
            elif score_standard > 0.8 and score_standard <= 0.9:
                score_position.append(0.04)
            elif score_standard > 0.9 and score_standard <= 1.0:
                score_position.append(0.15)
            else:
                score_position.append(0)
        return score_position

    def score_length(self, sentence):
        """
            文本长度得分
        :param sentence: 
        :return: 
        """
        score_length = 1 - min(abs(self.len_ideal - len(sentence)), self.len_ideal) / self.len_ideal
        return score_length

    def score_sbs(self, words):
        """
            单个句子的sbs分数
        :param words: 
        :return: 
        """
        score_sbs = 0.0
        for word in words:
            if word in self.word_freqs:
                score_sbs += self.word_freqs[word]
        return ((1.0 / abs(len(words))) if len(words) else 1e-9) * score_sbs

    def score_dbs(self, words):
        """
            单个句子的dbs分数
        :param words: 
        :return: 
        """
        words_all = list(self.word_freqs.keys())
        pun = len(set(words)&set(words_all)) + 1
        score_dbs = 0.0
        wf_first = []
        for i, word in enumerate(words):
            if word in words_all:
                index = words_all.index(word)
                if not wf_first:
                    wf_first = [index, self.word_freqs[word]]
                else:
                    score_dbs += wf_first[1]*self.word_freqs[word] / (((wf_first[0] - index) if (wf_first[0] - index)!=0 else self.len_words)**2)
        score_dbs = score_dbs if score_dbs !=0 else 1e-9
        return (1.0 / pun * (pun + 1.0)) * score_dbs

    def score_title(self, words):
        """
            与标题重合部分词语
        :param words: 
        :return: 
        """
        mix_word = [word for word in words if word in self.title]
        len_mix_word = len(mix_word)
        len_title_word = len(self.title)
        return (len_mix_word + 1.0) / (len_mix_word + 2.0) / len_title_word

    def summarize(self, text, num=6, title=None):
        # 切句
        if type(text) == str:
            self.sentences = cut_sentence(text)
        elif type(text) == list:
            self.sentences = text
        else:
            raise RuntimeError("text type must be list or str")
        self.title = title
        if self.title:
            self.title = jieba_cut(title)
        # 切词
        sentences_cut = [[word for word in jieba_cut(extract_chinese(sentence))
                             if word.strip()] for sentence in self.sentences]
        # 去除停用词等
        self.sentences_cut = [list(filter(lambda x: x not in self.stop_words, sc)) for sc in sentences_cut]
        # 词频统计
        self.words = []
        for sen in self.sentences_cut:
            self.words = self.words + sen
        self.word_count = dict(Counter(self.words))
        # word_count_rank = sorted(word_count.items(), key=lambda f:f[1], reverse=True)
        # self.word_freqs = [{'word':wcr[0], 'freq':wcr[1]} for wcr in word_count_rank]
        # 按频次计算词语的得分, 得到self.word_freq=[{'word':, 'freq':, 'score':}]
        self.word_freqs = {}
        self.len_words = len(self.words)
        for k, v in self.word_count.items():
            self.word_freqs[k] = v * 0.5 / self.len_words
        # 句子位置打分
        scores_posi = self.score_position()
        res_rank = {}
        self.res_score = []
        for i in range(len(sentences_cut)):
            sen = self.sentences[i] # 句子
            sen_cut = self.sentences_cut[i] # 句子中的词语
            score_sbs = self.score_sbs(sen_cut) # 句子中的词语打分1
            score_dbs = self.score_dbs(sen_cut) # 句子中的词语打分2
            score_word = (score_sbs + score_dbs) * 10.0 / 2.0 # 句子中的词语打分mix
            score_length = self.score_length(sen) # 句子文本长度打分
            score_posi = scores_posi[i]
            if self.title: # 有标题的文本打分合并
                score_title = self.score_title(sen_cut)
                score_total = (score_title * 0.5 + score_word * 2.0 + score_length * 0.5 + score_posi * 1.0) / 4.0
                # 可查阅各部分得分统计
                self.res_score.append(["score_total", "score_sbs", "score_dbs", "score_word", "score_length", "score_posi", "score_title", "sentences"])
                self.res_score.append([score_total, score_sbs, score_dbs, score_word, score_length, score_posi, score_title, self.sentences[i]])
            else: # 无标题的文本打分合并
                score_total = (score_word * 2.0 + score_length * 0.5 + score_posi * 1.0) / 3.5
                self.res_score.append(["score_total", "score_sbs", "score_dbs", "score_word", "score_length", "score_posi", "sentences"])
                self.res_score.append([score_total, score_sbs, score_dbs, score_word, score_length, score_posi, self.sentences[i].strip()])
            res_rank[self.sentences[i].strip()] = score_total
        # 最小句子数
        num_min = min(num, int(len(self.word_count) * 0.6))
        score_sen = [(rc[1], rc[0]) for rc in sorted(res_rank.items(), key=lambda d: d[1], reverse=True)][0:num_min]
        return score_sen


if __name__ == '__main__':
    doc1 = "PageRank算法简介。" \
          "是上世纪90年代末提出的一种计算网页权重的算法! " \
          "当时，互联网技术突飞猛进，各种网页网站爆炸式增长。 " \
          "业界急需一种相对比较准确的网页重要性计算方法。 " \
          "是人们能够从海量互联网世界中找出自己需要的信息。 " \
          "百度百科如是介绍他的思想:PageRank通过网络浩瀚的超链接关系来确定一个页面的等级。 " \
          "Google把从A页面到B页面的链接解释为A页面给B页面投票。 " \
          "Google根据投票来源甚至来源的来源，即链接到A页面的页面。 " \
          "和投票目标的等级来决定新的等级。简单的说， " \
          "一个高等级的页面可以使其他低等级页面的等级提升。 " \
          "具体说来就是，PageRank有两个基本思想，也可以说是假设。 " \
          "即数量假设：一个网页被越多的其他页面链接，就越重）。 " \
          "质量假设：一个网页越是被高质量的网页链接，就越重要。 " \
          "总的来说就是一句话，从全局角度考虑，获取重要的信。 "
    title = "方直科技等公司合伙设立教育投资基金"
    doc = "多知网5月26日消息，今日，方直科技发公告，拟用自有资金人民币1.2亿元，" \
          "与深圳嘉道谷投资管理有限公司、深圳嘉道功程股权投资基金（有限合伙）共同发起设立嘉道方直教育产业投资基金（暂定名）。" \
          "该基金认缴出资总规模为人民币3.01亿元。" \
          "基金的出资方式具体如下：出资进度方面，基金合伙人的出资应于基金成立之日起四年内分四期缴足，每期缴付7525万元；" \
          "各基金合伙人每期按其出资比例缴付。合伙期限为11年，投资目标为教育领域初创期或成长期企业。" \
          "截止公告披露日，深圳嘉道谷投资管理有限公司股权结构如下:截止公告披露日，深圳嘉道功程股权投资基金产权结构如下:" \
          "公告还披露，方直科技将探索在中小学教育、在线教育、非学历教育、学前教育、留学咨询等教育行业其他分支领域的投资。" \
          "方直科技2016年营业收入9691万元，营业利润1432万元，归属于普通股股东的净利润1847万元。（多知网 黎珊）}}"
    tt = TextTeaserSum()
    res_ = tt.summarize(doc)
    for res in res_:
        print(res)
    gg = 0
